#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <functional>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "InetAddr.hpp"
#include "Log.hpp"

using namespace LogModule;

static const int defaultfd = -1;
using func_t = std::function<void(int , const std::string& , InetAddr& )>;
class UdpServer{
public:
	UdpServer(uint16_t port, func_t func)
		:_port(port), _func(func), _sockfd(defaultfd), _isrunning(false)
	{}
	
	void Init(){
		_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
		if(_sockfd < 0){
			LOG(LogLevel::WARNING) << "SOCKET ERROR!!";
			exit(1);
		}
		LOG(LogLevel::INFO) << "SOCKET SUCCESS, SOCKET: " << _sockfd;
		
		struct sockaddr_in local;
		memset(&local, 0, sizeof(local));
		local.sin_family = AF_INET;
		local.sin_port = htons(_port);
		local.sin_addr.s_addr = INADDR_ANY;
		
		int n = bind(_sockfd, (struct sockaddr*)&local, sizeof(local));
		if(n < 0){
			LOG(LogLevel::WARNING) << "BIND ERROR";
			exit(2);
		}
		LOG(LogLevel::INFO) << "BIND SUCCESS";
	}
	
	void Start(){
		_isrunning = true;
		while(true){
			char buffer[128];
			struct sockaddr_in peer;
			socklen_t len = sizeof(peer);
			ssize_t s = recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr*)&peer, &len);
			if(s > 0){
				buffer[s] = 0;
				InetAddr inetaddr(peer);
				
				_func(_sockfd, buffer, inetaddr);
		
			}
		}
	}

	
private:
	func_t _func;
	int _sockfd;
	
	uint16_t _port;
	bool _isrunning;
	
};